package net.sk.china.front.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReUtil;
import net.sk.china.common.exception.TalkException;
import net.sk.china.common.model.user.User;
import net.sk.china.common.utils.DateUtil;
import net.sk.china.common.utils.RedisUtil;
import net.sk.china.common.utils.TalkUtil;
import net.sk.china.front.constants.Constants;
import net.sk.china.front.constants.RegularConstants;
import net.sk.china.front.request.LoginRequest;
import net.sk.china.front.request.RetrievePwdRequest;
import net.sk.china.front.response.LoginResponse;
import net.sk.china.front.service.LoginService;
import net.sk.china.front.service.user.UserService;
import net.sk.china.front.strategy.SmsService;
import net.sk.china.front.strategy.UserInterface;
import net.sk.china.front.strategy.UserLoginFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

/**
 * LoginServiceImpl 接口实现
 * +----------------------------------------------------------------------
 * // | Talk To [ 聊来改善地区金融服务环境，助力企业发展 ]
 * // +----------------------------------------------------------------------
 * // | Copyright (c) 2018-2024 聊来 All rights reserved.
 * // +----------------------------------------------------------------------
 * // | Licensed ( <a href="http://www.apache.org/licenses/LICENSE-2.0">apache</a> )
 * // +----------------------------------------------------------------------
 * // | @Author: 聊来 <18970881148@qq.com>
 * // +----------------------------------------------------------------------
 * // | DateTime: 2024/6/4 17:02
 * // +----------------------------------------------------------------------
 */

@Service
public class LoginServiceImpl implements LoginService {

    private static final Logger logger = LoggerFactory.getLogger(LoginServiceImpl.class);

    private final UserLoginFactory userLoginFactory;

    private final UserService userService;

    private final SmsService smsService;

    private RedisUtil redisUtil;

    public LoginServiceImpl(UserLoginFactory userLoginFactory, UserService userService, SmsService smsService, RedisUtil redisUtil) {
        this.userLoginFactory = userLoginFactory;
        this.userService = userService;
        this.smsService = smsService;
        this.redisUtil = redisUtil;
    }

    /**
     * 登录
     * @param request 请求对象
     * @param ip 客户端IP
     * @return {@code LoginResponse}
     */
    @Override
    public LoginResponse login(LoginRequest request, String ip) {
        UserInterface userInterface = userLoginFactory.getInterface(request.getType());
        if (userInterface == null) {
            throw new TalkException("登录方式不存在");
        }

        if (!ReUtil.isMatch(RegularConstants.USER_LOGIN_TYPE, request.getLoginType())) {
            throw new TalkException("用户登录类型不存在");
        }

        return userInterface.login(request, ip);
    }

    /**
     * 找回密码并登录
     * @param request 请求参数
     * @param ip 客户端IP
     * @return {@code LoinResponse}
     */
    @Override
    public LoginResponse retrievePassword(RetrievePwdRequest request, String ip) {
        User user = userService.getByAccount(request.getPhone());
        if (ObjectUtil.isNull(user)) {
            throw new TalkException("该手机号还未注册过，无法进行找回密码操作");
        }

        if (!ReUtil.isMatch(RegularConstants.USER_LOGIN_TYPE, request.getLoginType())) {
            throw new TalkException("用户登录类型不存在");
        }

        // 检测手机验证码
        smsService.checkValidateCode(request.getPhone(), "retrieve", request.getCaptcha());

        user.setPwd(TalkUtil.encryptPassword(request.getPassword(), request.getPhone()));
        user.setLoginType(request.getLoginType());
        user.setLastIp(ip);
        user.setLastLoginTime(DateUtil.getNowTime());

        if (!userService.updateById(user)) {
            logger.error(String.format("找回密码并登录失败，uid=%d", user.getUid()));
        }

        LoginResponse loginResponse = new LoginResponse();
        // 生成token
        try {
            redisUtil.delete(Constants.SMS_VALIDATE_PHONE + "retrieve" + ":" +  request.getPhone());
            String token = userService.createToken(user.getUid());
            loginResponse.setToken(token);
        } catch (Exception e) {
            logger.error(String.format("生成用户Token失败: %s", e.getMessage()));
        }
        loginResponse.setType("login");

        return loginResponse;
    }

    /**
     * 用户密码解密
     * @param pwd 密文
     * @param account 登录账号
     * @return {@code String}
     */
    @Override
    public String decryptPassword(String pwd, String account) { return TalkUtil.decryptPassword(pwd, account); }
}
